<?php

class PlatformService
{
    /**
     * @var PlatformService
     */
    private static $instance;

    /**
     * Get the instance of PlatformService.
     * @return PlatformService
     */
    public static function get()
    {
        if (!self::$instance) {
            self::$instance = new PlatformService();
        }
        return self::$instance;
    }

    /**
     * Construction.
     */
    private function __construct()
    {

    }

    /**
     * 游客切换到授权登录账户同步逻辑
     * @param array $platformInfo 新的授权平台信息
     * @param array $oldPlatformInfo 游客平台信息
     * @return array
     * @throws SzException
     */
    public function newPortPlayerUserId($platformInfo = [], $oldPlatformInfo = [])
    {
        $userId = null;
        $realUserId = null;
        $create = [];
        $returnPlatformInfo = [];

        // 判断授权ID是否有账号信息，有则直接返回
        foreach ($platformInfo as $platform => $platformId) {
            if (empty($platformId)) {
                continue;
            }

            $_platformId = $platformId;

            list($platform, $platformId) = $this->parsePlatformId($platform, $platformId);
            if (empty($platformId)) {
                continue;
            }
            /* @var ModuleSnsVo $portVo */
            $portVo = SzPersister::get()->getVo(null, ModuleSnsConst::ORM_NAME_SNS, $platformId);
            if ($portVo and $portVo->getUserId()) {
                $realUserId = $portVo->getUserId();
                $userId = $realUserId;

                UserService::get()->updateProfileInfo($userId, GameConst::USER_INFO_TYPE_PLATFORM, $_platformId);
                UserService::get()->updateProfileInfo($userId, GameConst::USER_INFO_TYPE_PLATFORM_INFO, $returnPlatformInfo);
                return $this->portPlayerUserId($platformInfo);
            }
        }

        foreach ($oldPlatformInfo as $platform => $platformId) {
            if (empty($platformId)) {
                continue;
            }

            list($platform, $platformId) = $this->parsePlatformId($platform, $platformId);
            if (empty($platformId)) {
                continue;
            }

            /* @var ModuleSnsVo $portVo */
            $portVo = SzPersister::get()->getVo(null, ModuleSnsConst::ORM_NAME_SNS, $platformId);
            if ($portVo) {
                if (is_null($userId)) {
                    $userId = $portVo->getUserId();
                } elseif ($userId != $portVo->getUserId()) {
                    // 原始用户不存在则使用授权用户openid创建新账号登录
                    return $this->portPlayerUserId($platformInfo);
                }
            } else {
                if (count($oldPlatformInfo) > 1) {
                    $this->portPlayerUserId($oldPlatformInfo, true);
                    continue;
                } else {
                    return $this->portPlayerUserId($oldPlatformInfo, true);
                }
            }
        }

        foreach ($platformInfo as $platform => $platformId) {
            if (empty($platformId)) {
                continue;
            }

            list($platform, $platformId) = $this->parsePlatformId($platform, $platformId);
            if (empty($platformId)) {
                continue;
            }
            /* @var ModuleSnsVo $portVo */
            $portVo = SzPersister::get()->getVo(null, ModuleSnsConst::ORM_NAME_SNS, $platformId);
            if (!$portVo or !$portVo->getUserId()) {
                if (!in_array($platformId, $create)) {
                    // 没有关系则创建
                    $create[] = $platformId;
                }
            }
            $returnPlatformInfo[$platform] = $platformId;
        }

        if (count($create) and $userId) {
            /* @var SzMySqlModel $model */
            foreach ($create as $platformId) {
                $portVo = new ModuleSnsVo($platformId, $userId, SzTime::getTime(), true);
                $model = SzPersister::get()->getModel(ModuleSnsConst::ORM_NAME_SNS);
                $portVo->setUserId($userId);
                $model->setVoCache($portVo);
                SzPersister::get()->setVo($portVo);
            }
        }
        return array($userId, $returnPlatformInfo);
    }

    public function portPlayerUserId($platformInfo, $bCreate = false)
    {
        $userId = null;
        $create = [];
        $returnPlatformInfo = [];
        foreach ($platformInfo as $platform => $platformId) {
            if (empty($platformId)) {
                continue;
            }
            list($platform, $platformId) = $this->parsePlatformId($platform, $platformId);
            if (empty($platformId)) {
                continue;
            }
            /* @var ModuleSnsVo $portVo */
            $portVo = SzPersister::get()->getVo(null, ModuleSnsConst::ORM_NAME_SNS, $platformId);
            if ($portVo) {
                if (is_null($userId)) {
                    $userId = $portVo->getUserId();
                } elseif ($userId != $portVo->getUserId()) {
                    throw new SzException(20049);
                }
            } else {
                if (!in_array($platformId, $create)) {
                    $create[] = $platformId;
                }
            }
            $returnPlatformInfo[$platform] = $platformId;
        }
        if ($bCreate && $create) {
            /* @var SzMySqlModel $model */
            $model = SzPersister::get()->getModel(ModuleSnsConst::ORM_NAME_SNS);
            foreach ($create as $platformId) {
                $portVo = new ModuleSnsVo($platformId, $userId, SzTime::getTime(), true);
                if (is_null($userId)) {
                    list($affected, $insertId) = $model->insert($portVo); // we need the userId to be created immediately, so insert here
                    if ($insertId) {
                        $userId = $insertId;
                        $portVo->setUserId($userId);
                        $portVo->removeInsertFlag();
                        $model->setVoCache($portVo);
                        SzPersister::get()->setVo($portVo);
                    }
                } else {
                    SzPersister::get()->setVo($portVo);
                }
            }
        }
        return array($userId, $returnPlatformInfo);
    }

    public function parsePlatformId($platform, $platformId)
    {
        if ($platform == "SzSdk" || $platform == "sdk_id") {//sdk_id为用户的唯一识别Id
            $platform = 'sdk';
            $platformId = 'sdk_' . $platformId;
        } else if ($platform == "facebook" || $platform == "fb_id") {//为FaceBook用户
            $platform = 'fb';
            $platformId = 'fb_' . $platformId;
        } else if ($platform == "google" || $platform == "gg_id") {//Google用户
            $platform = 'gg';
            $platformId = 'gg_' . $platformId;
        } else if ($platform == "gameCenter" || $platform == "gc_id") {//GameCenter用户
            $platform = 'gc';
            $platformId = 'gc_' . $platformId;
        } else if ($platform == "shinezone" || $platform == "sz_id") {//炫踪平台用户
            $platform = 'sz';
            $platformId = 'sz_' . $platformId;
        } else if ($platform == "H5WeChat" || $platform == "wc_id" || $platform == "weChat") {//微信平台用户
            $platform = 'wc';
            $platformId = 'wc_' . $platformId;
        } else if ($platform == "qq" || $platform == "QQ") {//手Q平台用户
            $platform = 'qq';
            $platformId = 'qq_' . $platformId;
        } else if ($platform == "tt" || $platform == "TT") {//头条平台用户
            $platform = 'tt';
            $platformId = 'tt_' . $platformId;
        }else if ($platform == "dev") {

        } else {
            $platformId = null;
        }
        return array($platform, $platformId);
    }

    /**
     * 根据用户id生成 platform 对象
     *
     * @param $userId
     * @return PlatformBase
     */
    public static function getPlatformInstanceByUserId($userId)
    {
        $platform = UserService::get()->getInfo($userId, GameConst::USER_INFO_TYPE_USER_PLATFORM);
        return self::getPlatformInstance($platform);
    }

    /**
     * 根据平台类型生成 platform 对象
     *
     * @param $platform
     * @return PlatformBase
     * @throws SzException
     */
    public static function getPlatformInstance($platform)
    {
        $paymentInstance = null;
        switch ($platform) {
            case PlatformBase::PLATFORM_H5_WE_CHAT:
                $paymentInstance = PlatformH5WeChat::get();
                break;
            case PlatformBase::PLATFORM_SZ_SDK:
                $paymentInstance = PlatformSzSdk::get();
                break;
            case PlatformBase::PLATFORM_DEV:
                $paymentInstance = PlatformDev::get();
                break;
            case PlatformBase::PLATFORM_QQ:
                $paymentInstance = PlatformQQ::get();
                break;
            case PlatformBase::PLATFORM_FACEBOOK:
                $paymentInstance = PlatformFacebook::get();
                break;
            case PlatformBase::PLATFORM_TT:
                $paymentInstance = PlatformTT::get();
                break;
            default:
                throw new SzException(20046, 'platform error');
        }
        return $paymentInstance;
    }

    /**
     * 验证token
     * @param $platform
     * @param $platformId
     * @param $token
     * @return bool
     */
    public function checkToken($platform, $platformId, $token)
    {
        return self::getPlatformInstance($platform)->checkToken($platformId, $token);
    }

    /**
     * Post a http request.
     *
     * @param string $url
     * @param array $params 'key => value', if string given means this query data already formatted
     * @param boolean $needEncode default true
     * @param int $timeout default 100 => 100s
     * @param bool $unpack default 是否使用msgpack_pack
     * @param bool $throwError default true
     * @throws SzException 10200
     * @return array $result
     */
    public static function postHttpRequest($url, $params, $unpack = false, $needEncode = true, $timeout = 60, $throwError = true)
    {
        $result = null;
        if ($unpack && !function_exists('msgpack_pack')) {
            throw new SzException(20039);
        }
        $queryString = is_array($params) ? ($unpack ? msgpack_pack($params) : SzUtility::buildQueryString($params, $needEncode)) : $params;
        // post the query and get result
        if (function_exists('curl_init')) {
            // Use CURL if installed...
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); // default connect timeout 10s
            curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
            curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $queryString);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $result = curl_exec($ch);
            if (false === $result) {
                $error_no = curl_errno($ch);
                $error = curl_error($ch);
                curl_close($ch);
                if ($throwError) {
                    throw new SzException(10200, array($error_no, $error));
                } else {
                    return [$error_no, $error];
                }
            }
            curl_close($ch);
        } else {
            // Non-CURL based version...
            $context = array(
                'http' => array(
                    'method' => 'POST',
                    'header' => 'Content-type: application/x-www-form-urlencoded' . "\r\n" . 'User-Agent: PHP5 Framework ' . "\r\n" . 'Content-length: ' . strlen($queryString),
                    'content' => $queryString
                ),
            );
            $contextId = stream_context_create($context);
            $sock = fopen($url, 'r', false, $contextId);
            if ($sock) {
                $result = '';
                while (!feof($sock)) {
                    $result .= fgets($sock, 4096);
                }
                fclose($sock);
            }
        }

        if ($result) {
            if ($unpack) {
                $result = msgpack_unpack($result);
            } else {
                $result = json_decode($result, true);
            }
        }

        return $result;
    }
}
